/**
  @file: Domain.java
  
   PURPOSE:
      This class represents an instance of a Domain, either logical or physical.
   
   @author Ron Williams
  
   REVISION HISTORY ABSTRACT
  
   PROGRAMMER:  Ron Williams ORG: MSE
  
   Copyright 2011 Mission Solutions LLC. All rights reserved.
  
   END ABSTRACT
 */

package com.mse.utilities;

import java.lang.String;
import java.lang.System;
import java.util.ArrayList;

import com.mse.utilities.DomainId;
import com.mse.utilities.DomainHost;
import com.mse.utilities.DomainHostArchDef;
import com.mse.utilities.DomainException;
import com.mse.utilities.UtilityException;

/**
   DESCRIPTION:
      The Domain class contains the information as a result of parsing a
      Domain Definition file.
 */
public class Domain {

   /**
      DESCRIPTION:
         Create a Domain object.
      @return void
      @throws n/a
    */
   public Domain(DomainId did) {
      this.domainId     = did;
      this.hostArchDefs = new ArrayList<DomainHostArchDef>();
      this.domainHosts  = new ArrayList<DomainHost>();
      this.hostGroups   = new ArrayList<DomainHostGroup>();
   }

   /**
      DESCRIPTION:
         get the DomainId for this Domain.
      @return did - the DomainId for this Domain
      @throws n/a
    */
   public DomainId getDomainId() {
      return this.domainId;
   }

   /**
      DESCRIPTION:
         determine if this is a "logical" domain (DomainId for this Domain is
         "logical").
      @return boolean - true means "logical" domain, false means "physical"
      @throws n/a
    */
   public boolean isDomainLogical() {
      return this.domainId.isDomainLogical();
   }

   /**
      DESCRIPTION:
         set host architecture definitions the for this Domain.

         It is assumed that all DomainHostArchDef objects passed are unique!

      @param hostArchDefs - container of definitions
      @return void
      @throws n/a
    */
   public void setHostArchDefs(ArrayList<DomainHostArchDef> hostArchDefs) {
      this.hostArchDefs.addAll(hostArchDefs);
   }

   /**
      DESCRIPTION:
         add a host architecture definition to this Domain.

      @param hostArchDef - definition to add
      @return void
      @throws DomainException - if the architecture definition is not unique
    */
   public void addHostArchDef(DomainHostArchDef hostArchDef)
      throws DomainException{

      for (DomainHostArchDef archDef : hostArchDefs) {
         if (archDef.equals(hostArchDef)) {
            throw new DomainException("HostArchDef: " +
                            hostArchDef.getArchId() + ", is NOT UNIQUE");
         }
      }

      this.hostArchDefs.add(hostArchDef);
   }

   /**
      DESCRIPTION:
         get host architecture definitions the for this Domain.

      @return hostArchDefs - container of definitions
      @throws n/a
    */
   public ArrayList<DomainHostArchDef> getAllHostArchDefs() {
      return this.hostArchDefs;
   }

   /**
      DESCRIPTION:
         get host architecture definition having the specified "ArchID".

      @param archId - an ArchID value of the "HostArchDef" object to return
      @return hostArchDef - the HostArchDef object matching the "archId" or
                            null if not found!
      @throws n/a
    */
   public DomainHostArchDef getHostArchDef(String archId) {
      DomainHostArchDef hostArchDef = null;  // assume not found

      for (DomainHostArchDef item : this.hostArchDefs) {
         if (archId.equals(item.getArchId()) ) {
            hostArchDef = item;
            break;
         }
      }
      return hostArchDef;
   }

   /**
      DESCRIPTION:
         add a host definition to this Domain.

      @param hostDef - host definition to add
      @return void
      @throws DomainException - if the host definition is not unique
    */
   public void addHostDef(DomainHost hostDef) throws DomainException{

      String targetHID = hostDef.getHID();

      for (DomainHost host : domainHosts) {
         if (targetHID.equals(host.getHID()) ) {
            throw new DomainException("HostDef: " + targetHID +
                                      ", is NOT UNIQUE");
         }
      }
      this.domainHosts.add(hostDef);
   }

   /**
      DESCRIPTION:
         get a host definition from this Domain.

      @param hid - host id of host to get
      @return hostDef - host definition or null if not found!
      @throws n/a
    */
   public DomainHost getHostDef(String hid) throws DomainException{
      DomainHost rtnHost = null;

      for (DomainHost host : domainHosts) {
         if (hid.equals(host.getHID()) ) {
            rtnHost = host;
            break;
         }
      }

      return rtnHost;
   }

   /**
      DESCRIPTION:
         determine if a host is in this Domain.

      @param hid - host identifier
      @return boolean - true, the specified host identifier is in this domain
                        false, otherwise
    */
   public boolean isHostInDomain(String hid) {
      boolean rslt = false;      // assume host is not in this domain

      for (DomainHost host : domainHosts) {
         if (hid.equals(host.getHID()) ) {
            rslt = true;
            break;
         }
      }

      return rslt;
   }


   /**
      DESCRIPTION:
         add a host group definition to this Domain.

      @param group - host group to add
      @return void
      @throws DomainException - if the host group is not unique
    */
   public void addHostGroup(DomainHostGroup group) throws DomainException{

      String gid = group.getGID();

      for (DomainHostGroup item : hostGroups) {
         if (gid.equals(item.getGID()) ) {
            throw new DomainException("HostGroup: " + gid +
                                      ", is NOT UNIQUE");
         }
         // now validate that all the hosts in the "group" are NOT in any
         // other host group that we know about!

         for (DomainHost aHost : group.getAllHosts()) {
            if (item.hostInGroup(aHost) ) {
               throw new DomainException("\n*** ERROR in HostGroup: " + gid + 
                  ". It has host: " + aHost.getHID() +
                  ", but also in HostGroup: " + item.getGID() +
                  ". Hosts can only be in one group.");
            }
         }
      }

      this.hostGroups.add(group);
   }

   /**
      DESCRIPTION:
         get a host group definition from this Domain for a specified host
         group id. Null is returned if the group identifier is not found in
         this Domain.

      @param gid - host group to get
      @return group - the host group or null if not found
      @throws DomainException - if the host group is not unique
    */
   public DomainHostGroup getHostGroup(String gid) {
      DomainHostGroup group = null;

      for (DomainHostGroup item : hostGroups) {
         if (gid.equals(item.getGID()) ) {
            group = item;
            break;
         }
      }
      return group;
   }


   /**
      DESCRIPTION:
         get host identifiers for all hosts in a HostGroup. An empty container
         is returned if the specified host group in not in this domain.

      @param gid - host group identifier
      @return hids - container of Host Identifiers for all hosts in the
   `                 specified Host Group
    */
   public ArrayList<String> getHIDsForGroup(String gid) {
      ArrayList<String> hList = new ArrayList<String>();

      for (DomainHostGroup item : hostGroups) {
         if (gid.equals(item.getGID()) ) {
            for (DomainHost aHost : item.getAllHosts()) {
               hList.add(aHost.getHID());
            }
            break;
         }
      }

      return hList;
   }

   /**
      DESCRIPTION:
         get DomainHostGroup for a host. 

      @param host - host whose group is to be returned
      @return dhg - DomainHostGroup for the host, or null if the host is not
   `                part of any group
    */
   public DomainHostGroup getGroupForHost(DomainHost host) {
      DomainHostGroup group = null;

      for (DomainHostGroup aGroup : hostGroups) {
         if (aGroup.hostInGroup(host)) {
            group = aGroup;
            break;
         }
      }

      return group;
   }

   /**
      DESCRIPTION:
         determine if a group is in this Domain.

      @param gid - group identifier
      @return boolean - true, the specified group identifier is in this domain
                        false, otherwise
    */
   public boolean isGroupInDomain(String gid) {
      boolean rslt = false;      // assume group is not in this domain

      for (DomainHostGroup group : hostGroups) {
         if (gid.equals(group.getGID()) ) {
            rslt = true;
            break;
         }
      }

      return rslt;
   }

    /**
     * DESCRIPTION:
     * <p>
     * returns list of all hosts
     * @return list of all hosts
     */
    public ArrayList<DomainHost> getDomainHosts() {
        return domainHosts;
    }
    
    /**
     * DESCRIPTION:
     * <p>
     * returns list of all groups
     * @return list of all groups
     */
    public ArrayList<DomainHostGroup> getHostGroups() {
        return hostGroups;
    }
    
   private DomainId domainId;
   private ArrayList<DomainHostArchDef> hostArchDefs;
   private ArrayList<DomainHost> domainHosts;
   private ArrayList<DomainHostGroup> hostGroups;

}

